<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>daily study | daily study</title>
    <meta name="description" content="无 FUCK 说">
    <link rel="preload stylesheet" href="/assets/style.1ac9090e.css" as="style">
    <link rel="modulepreload" href="/assets/app.db63b7d7.js">
    <link rel="modulepreload" href="/assets/interview_工程化.md.deda9421.lean.js">
    
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-c3073c68><!--[--><!--]--><!--[--><span tabindex="-1" data-v-151f2593></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-151f2593> Skip to content </a><!--]--><!----><header class="VPNav" data-v-c3073c68 data-v-0fa0e57d><div class="VPNavBar has-sidebar" data-v-0fa0e57d data-v-be450ad9><div class="container" data-v-be450ad9><div class="title" data-v-be450ad9><div class="VPNavBarTitle has-sidebar" data-v-be450ad9 data-v-6d2fb2d9><a class="title" href="/" data-v-6d2fb2d9><!--[--><!--]--><!--[--><img class="VPImage logo" src="/coll.png" alt data-v-6db2186b><!--]--><!--[--> <!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-be450ad9><div class="curtain" data-v-be450ad9></div><div class="content-body" data-v-be450ad9><!--[--><!--]--><!----><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-be450ad9 data-v-bdedfc22><span id="main-nav-aria-label" class="visually-hidden" data-v-bdedfc22>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->HOME<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/article/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->随笔<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/engineering/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->工程化<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink active" href="/interview/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->前端笔面试题<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/javascript/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->JS<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/vue/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->Vue<!--]--><!----></a><!--]--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/node/" data-v-bdedfc22 data-v-f2ec7ecf data-v-a8b5c975><!--[-->Node<!--]--><!----></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-be450ad9 data-v-da3f667a><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-da3f667a data-v-0d529b6d data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-0d529b6d><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-0d529b6d><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-be450ad9 data-v-2ab2a029 data-v-f6988cfb><!--[--><a class="VPSocialLink" href="https://github.com/hmfy" target="_blank" rel="noopener" data-v-f6988cfb data-v-e57698f6><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-be450ad9 data-v-66bb1f24 data-v-96001b6b><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-96001b6b><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-96001b6b><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-96001b6b><div class="VPMenu" data-v-96001b6b data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-66bb1f24><div class="item appearance" data-v-66bb1f24><p class="label" data-v-66bb1f24>Appearance</p><div class="appearance-action" data-v-66bb1f24><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-label="toggle dark mode" aria-checked="false" data-v-66bb1f24 data-v-0d529b6d data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-0d529b6d><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-0d529b6d><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-66bb1f24><div class="item social-links" data-v-66bb1f24><div class="VPSocialLinks social-links-list" data-v-66bb1f24 data-v-f6988cfb><!--[--><a class="VPSocialLink" href="https://github.com/hmfy" target="_blank" rel="noopener" data-v-f6988cfb data-v-e57698f6><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-be450ad9 data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav" data-v-c3073c68 data-v-2817d72e><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-2817d72e><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-2817d72e><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-2817d72e>Menu</span></button><a class="top-link" href="#" data-v-2817d72e>Return to top</a></div><aside class="VPSidebar" data-v-c3073c68 data-v-c79ccefa><div class="curtain" data-v-c79ccefa></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-c79ccefa><span class="visually-hidden" id="sidebar-aria-label" data-v-c79ccefa> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-c79ccefa><section class="VPSidebarItem level-0 has-active" data-v-c79ccefa data-v-983f6b21><!----><div class="items" data-v-983f6b21><!--[--><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/index.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>简介</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/css-note.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>css-note</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/javascript.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>javascript</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/promise.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>promise</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/vue.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>vue</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link is-active has-active" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/%E5%B7%A5%E7%A8%8B%E5%8C%96.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>工程化</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/%E6%B5%8F%E8%A7%88%E5%99%A8.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>浏览器</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-983f6b21 data-v-983f6b21><div class="item" data-v-983f6b21><div class="indicator" data-v-983f6b21></div><a class="VPLink link link" href="/interview/%E7%BD%91%E7%BB%9C.html" data-v-983f6b21 data-v-a8b5c975><!--[--><p class="text" data-v-983f6b21>网络</p><!--]--><!----></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-c3073c68 data-v-4e6b5525><div class="VPDoc has-sidebar has-aside" data-v-4e6b5525 data-v-ae7d01fc><div class="container" data-v-ae7d01fc><div class="aside" data-v-ae7d01fc><div class="aside-curtain" data-v-ae7d01fc></div><div class="aside-container" data-v-ae7d01fc><div class="aside-content" data-v-ae7d01fc><div class="VPDocAside" data-v-ae7d01fc data-v-cdc66372><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline has-outline" data-v-cdc66372 data-v-4414ac5c><div class="content" data-v-4414ac5c><div class="outline-marker" data-v-4414ac5c></div><div class="outline-title" data-v-4414ac5c>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-4414ac5c><span class="visually-hidden" id="doc-outline-aria-label" data-v-4414ac5c> Table of Contents for current page </span><ul class="root" data-v-4414ac5c data-v-1188541a><!--[--><li data-v-1188541a><a class="outline-link" href="#_1-下面的模块导出了什么结果" data-v-1188541a>1. 下面的模块导出了什么结果？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_2-说一下你对前端工程化-模块化-组件化的理解" data-v-1188541a>2. 说一下你对前端工程化，模块化，组件化的理解？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_3-webpack-和-gulp-的区别是什么" data-v-1188541a>3. webpack 和 gulp 的区别是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_4-webpack-中的-loader-属性和-plugins-属性的区别是什么" data-v-1188541a>4. webpack 中的 loader 属性和 plugins 属性的区别是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_5-webpack-的核心概念都有哪些" data-v-1188541a>5. webpack 的核心概念都有哪些？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_6-commonjs-和-es6-模块的区别是什么" data-v-1188541a>6. commonjs 和 es6 模块的区别是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_7-es6-中如何实现模块化的异步加载" data-v-1188541a>7. ES6 中如何实现模块化的异步加载？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_8-说一下-webpack-中的几种-hash-的实现原理是什么" data-v-1188541a>8. 说一下 webpack 中的几种 hash 的实现原理是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_9-webpack-如果使用了-hash-命名-那是每次都会重新生成-hash-吗" data-v-1188541a>9. webpack 如果使用了 hash 命名，那是每次都会重新生成 hash 吗？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_10-webpack-中是如何处理图片的-抖音直播" data-v-1188541a>10. webpack 中是如何处理图片的？ （抖音直播）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_11-webpack-打包出来的-html-为什么-style-放在头部-script-放在底部" data-v-1188541a>11. webpack 打包出来的 html 为什么 style 放在头部 script 放在底部？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_12-webpack-配置如何实现开发环境不使用-cdn、生产环境使用-cdn" data-v-1188541a>12. webpack 配置如何实现开发环境不使用 cdn、生产环境使用 cdn？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_13-介绍一下-webpack4-中的-tree-shaking-的工作流程" data-v-1188541a>13. 介绍一下 webpack4 中的 tree-shaking 的工作流程？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_14-说一下-webpack-loader-的作用是什么" data-v-1188541a>14. 说一下 webpack loader 的作用是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_15-在开发过程中如果需要对已有模块进行扩展-如何进行开发保证调用方不受影响" data-v-1188541a>15. 在开发过程中如果需要对已有模块进行扩展，如何进行开发保证调用方不受影响？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_16-export-和-export-default-的区别是什么" data-v-1188541a>16. export 和 export default 的区别是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_17-webpack-打包原理是什么" data-v-1188541a>17. webpack 打包原理是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_18-webpack-热更新原理是什么" data-v-1188541a>18. webpack 热更新原理是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_19-如何优化-webpack-的打包速度" data-v-1188541a>19. 如何优化 webpack 的打包速度？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_20-webpack-如何实现动态导入" data-v-1188541a>20. webpack 如何实现动态导入？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_21-说一下-webpack-有哪几种文件指纹" data-v-1188541a>21. 说一下 webpack 有哪几种文件指纹</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_22-常用的-webpack-loader-都有哪些" data-v-1188541a>22. 常用的 webpack Loader 都有哪些？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_23-说一下-webpack-常用插件都有哪些" data-v-1188541a>23. 说一下 webpack 常用插件都有哪些？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_24-使用-babel-loader-会有哪些问题-可以怎样优化" data-v-1188541a>24. 使用 babel-loader 会有哪些问题，可以怎样优化？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_25-babel-是如何对-class-进行编译的" data-v-1188541a>25. babel 是如何对 class 进行编译的？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_26-解释一下-babel-polyfill-的作用是什么" data-v-1188541a>26. 解释一下 babel-polyfill 的作用是什么？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_27-解释一下-less-的-的操作符是做什么用的" data-v-1188541a>27. 解释一下 less 的&amp;的操作符是做什么用的？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_28-在前端工程化中-可以进行哪些方面的优化" data-v-1188541a>28. 在前端工程化中，可以进行哪些方面的优化？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_29-如果有一个工程打包特别大-如何进行优化" data-v-1188541a>29. 如果有一个工程打包特别大-如何进行优化？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_30-webpack-怎么进行首屏加载的优化" data-v-1188541a>30. webpack 怎么进行首屏加载的优化？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_31-介绍一下-webpack-scope-hoisting" data-v-1188541a>31. 介绍一下 webpack scope hoisting？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_32-webpack-proxy-工作原理-为什么能解决跨域" data-v-1188541a>32. webpack proxy 工作原理，为什么能解决跨域？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_33-组件发布的是不是所有依赖这个组件库的项目都需要升级" data-v-1188541a>33. 组件发布的是不是所有依赖这个组件库的项目都需要升级？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_34-开发过程中-如何进行公共组件的设计-字节跳动" data-v-1188541a>34. 开发过程中，如何进行公共组件的设计？（字节跳动）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_35-说一下项目里有做过哪些-webpack-上的优化-字节跳动" data-v-1188541a>35. 说一下项目里有做过哪些 webpack 上的优化（字节跳动）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_36-具体说一下-splitchunksplugin-的使用场景及使用方法。-字节跳动" data-v-1188541a>36. 具体说一下 splitchunksplugin 的使用场景及使用方法。（字节跳动）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_37-描述一下-webpack-的构建流程-cvte" data-v-1188541a>37. 描述一下 webpack 的构建流程？（CVTE）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_38-解释一下-webpack-插件的实现原理-cvte" data-v-1188541a>38. 解释一下 webpack 插件的实现原理？（CVTE）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_39-有用过哪些插件做项目的分析吗-cvte" data-v-1188541a>39. 有用过哪些插件做项目的分析吗？（CVTE）</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_40-什么是-babel-有什么作用" data-v-1188541a>40. 什么是 babel，有什么作用？</a><!----></li><li data-v-1188541a><a class="outline-link" href="#_41-解释一下-npm-模块安装机制是什么" data-v-1188541a>41. 解释一下 npm 模块安装机制是什么？</a><!----></li><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-cdc66372></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-ae7d01fc><div class="content-container" data-v-ae7d01fc><!--[--><!--]--><main class="main" data-v-ae7d01fc><div style="position:relative;" class="vp-doc _interview_%E5%B7%A5%E7%A8%8B%E5%8C%96" data-v-ae7d01fc><div><h2 id="_1-下面的模块导出了什么结果" tabindex="-1">1. 下面的模块导出了什么结果？ <a class="header-anchor" href="#_1-下面的模块导出了什么结果" aria-hidden="true">#</a></h2><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight" tabindex="0"><code><span class="line"><span style="color:#89DDFF;">exports.</span><span style="color:#A6ACCD;">a </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">module.exports.</span><span style="color:#A6ACCD;">b </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">b</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">this.</span><span style="color:#A6ACCD;">c </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">c</span><span style="color:#89DDFF;">&#39;</span><span style="color:#89DDFF;">;</span></span>
<span class="line"><span style="color:#89DDFF;">module.exports</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">{</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F07178;">d</span><span style="color:#89DDFF;">:</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">d</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre></div><blockquote><p>参考答案：</p><div class="language-js"><button title="Copy Code" class="copy"></button><span class="lang">js</span><pre class="shiki material-theme-palenight" tabindex="0"><code><span class="line"><span style="color:#89DDFF;">{</span><span style="color:#F07178;"> </span><span style="color:#FFCB6B;">d</span><span style="color:#89DDFF;">:</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">d</span><span style="color:#89DDFF;">&#39;</span><span style="color:#F07178;"> </span><span style="color:#89DDFF;">}</span></span>
<span class="line"></span></code></pre></div></blockquote><h2 id="_2-说一下你对前端工程化-模块化-组件化的理解" tabindex="-1">2. 说一下你对前端工程化，模块化，组件化的理解？ <a class="header-anchor" href="#_2-说一下你对前端工程化-模块化-组件化的理解" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>这三者中，模块化是基础，没有模块化，就没有组件化和工程化</p><p>模块化的出现，解决了困扰前端的两大难题：全局污染问题和依赖混乱问题，从而让精细的拆分前端工程成为了可能。</p><p>工程化的出现，解决了前端开发环境和生产环境要求不一致的矛盾。在开发环境中，我们希望代码使用尽可能的细分，代码格式尽可能的统一和规范，而在生产环境中，我们希望代码尽可能的被压缩、混淆，尽可能的优化体积。工程化的出现，就是为了解决这一矛盾，它可以让我们舒服的在开发环境中书写代码，然后经过打包，生成最合适的生产环境代码，这样就解放了开发者的精力，让开发者把更多的注意力集中在开发环境上即可。</p><p>组件化开发是一些前端框架带来的概念，它把一个网页，或者一个站点，甚至一个完整的产品线，划分为多个小的组件，组件是一个可以复用的单元，它包含了一个某个区域的完整功能。这样一来，前端便具备了开发复杂应用的能力。</p></blockquote><h2 id="_3-webpack-和-gulp-的区别是什么" tabindex="-1">3. webpack 和 gulp 的区别是什么？ <a class="header-anchor" href="#_3-webpack-和-gulp-的区别是什么" aria-hidden="true">#</a></h2><blockquote><p>直播讲解</p></blockquote><blockquote><p>参考答案：</p><p>webpack 是基于模块化的构建工具，gulp 是基于工作流的构建工具。</p><p>webpack 是一个打包器，它以一个入口为起点，构建出整个项目的依赖关系图，然后进行打包合并，生成打包结果。</p><p>gulp 是一个过程管理器，每一步做什么完全看开发人员如何配置，把每一个步骤连接起来形成一个完整的构建流水线。</p><p>这两者并不矛盾，完全可以在一个工程中同时使用 webpack 和 gulp，将 webpack 作为 gulp 流水线中的一环。</p></blockquote><h2 id="_4-webpack-中的-loader-属性和-plugins-属性的区别是什么" tabindex="-1">4. webpack 中的 loader 属性和 plugins 属性的区别是什么？ <a class="header-anchor" href="#_4-webpack-中的-loader-属性和-plugins-属性的区别是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>它们都是 webpack 功能的扩展点。</p><p>loader 是加载器，主要用于代码转换，比如 JS 代码降级，CSS 预编译、模块化等</p><p>plugins 是插件，webpack 打包流程中每个环节都提供了钩子函数，可以利用这些钩子函数参与到打包生命周期中，更改或增加 webpack 的某些功能，比如生成页面和 css 文件、压缩打包结果等</p></blockquote><h2 id="_5-webpack-的核心概念都有哪些" tabindex="-1">5. webpack 的核心概念都有哪些？ <a class="header-anchor" href="#_5-webpack-的核心概念都有哪些" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ul><li><p>loader</p><p>加载器，主要用于代码转换，比如 JS 代码降级，CSS 预编译、模块化等</p></li><li><p>plugin</p><p>插件，webpack 打包流程中每个环节都提供了钩子函数，可以利用这些钩子函数参与到打包生命周期中，更改或增加 webpack 的某些功能，比如生成页面和 css 文件、压缩打包结果等</p></li><li><p>module</p><p>模块。webpack 将所有依赖均视为模块，无论是 js、css、html、图片，统统都是模块</p></li><li><p>entry</p><p>入口。打包过程中的概念，webpack 以一个或多个文件作为入口点，分析整个依赖关系。</p></li><li><p>chunk</p><p>打包过程中的概念，一个 chunk 是一个相对独立的打包过程，以一个或多个文件为入口，分析整个依赖关系，最终完成打包合并</p></li><li><p>bundle</p><p>webpack 打包结果</p></li><li><p>tree shaking</p><p>树摇优化。在打包结果中，去掉没有用到的代码。</p></li><li><p>HMR</p><p>热更新。是指在运行期间，遇到代码更改后，无须重启整个项目，只更新变动的那一部分代码。</p></li><li><p>dev server</p><p>开发服务器。在开发环境中搭建的临时服务器，用于承载对打包结果的访问</p></li></ul></blockquote><h2 id="_6-commonjs-和-es6-模块的区别是什么" tabindex="-1">6. commonjs 和 es6 模块的区别是什么？ <a class="header-anchor" href="#_6-commonjs-和-es6-模块的区别是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li>CMJ 是社区标准，ESM 是官方标准</li><li>CMJ 是使用 API 实现的模块化，ESM 是使用新语法实现的模块化</li><li>CMJ 仅在 node 环境中支持，ESM 各种环境均支持</li><li>CMJ 是动态的依赖，ESM 既支持动态，也支持静态</li><li>ESM 导入时有符号绑定，CMJ 只是普通函数调用和赋值</li></ol></blockquote><h2 id="_7-es6-中如何实现模块化的异步加载" tabindex="-1">7. ES6 中如何实现模块化的异步加载？ <a class="header-anchor" href="#_7-es6-中如何实现模块化的异步加载" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>使用动态导入即可，导入后，得到的是一个 Promise，完成后，得到一个模块对象，其中包含了所有的导出结果。</p></blockquote><h2 id="_8-说一下-webpack-中的几种-hash-的实现原理是什么" tabindex="-1">8. 说一下 webpack 中的几种 hash 的实现原理是什么？ <a class="header-anchor" href="#_8-说一下-webpack-中的几种-hash-的实现原理是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ul><li><p>hash</p><p>hash 是跟整个项目的构建相关，只要项目里有文件更改，整个项目构建的 hash 值都会更改，并且全部文件都共用相同的 hash 值</p></li><li><p>chunkhash</p><p>每个打包过程单独的 hash 值，如果一个项目有多个 entry，则每个 entry 维护自己的 chunkhash。</p></li><li><p>contenthash</p><p>每个文件内容单独的 hash 值，它和打包结果文件内容有关，只要文件内容不变，contenthash 不变。</p></li></ul></blockquote><h2 id="_9-webpack-如果使用了-hash-命名-那是每次都会重新生成-hash-吗" tabindex="-1">9. webpack 如果使用了 hash 命名，那是每次都会重新生成 hash 吗？ <a class="header-anchor" href="#_9-webpack-如果使用了-hash-命名-那是每次都会重新生成-hash-吗" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>不会。它跟关联的内容是否有变化有关系，如果没有变化，hash 就不会变。具体来说，contenthash 和具体的打包文件内容有关，chunkhash 和某一 entry 为起点的打包过程中涉及的内容有关，hash 和整个工程所有模块内容有关。</p></blockquote><h2 id="_10-webpack-中是如何处理图片的-抖音直播" tabindex="-1">10. webpack 中是如何处理图片的？ （抖音直播） <a class="header-anchor" href="#_10-webpack-中是如何处理图片的-抖音直播" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>webpack 本身不处理图片，它会把图片内容仍然当做 JS 代码来解析，结果就是报错，打包失败。如果要处理图片，需要通过 loader 来处理。其中，url-loader 会把图片转换为 base64 编码，然后得到一个 dataurl，file-loader 则会将图片生成到打包目录中，然后得到一个资源路径。但无论是哪一种 loader，它们的核心功能，都是把图片内容转换成 JS 代码，因为只有转换成 JS 代码，webpack 才能识别。</p></blockquote><h2 id="_11-webpack-打包出来的-html-为什么-style-放在头部-script-放在底部" tabindex="-1">11. webpack 打包出来的 html 为什么 style 放在头部 script 放在底部？ <a class="header-anchor" href="#_11-webpack-打包出来的-html-为什么-style-放在头部-script-放在底部" aria-hidden="true">#</a></h2><blockquote><p>说明：这道题的表述是有问题的，webpack 本身并不打包 html，相反，它如果遇到 html 代码会直接打包失败，因为 webpack 本身只能识别 JS。之所以能够打包出 html 文件，是因为插件或 loader 的作用，其中，比较常见的插件是 html-webpack-plugin。所以这道题的正确表述应该是：「html-webpack-plugin 打包出来的 html 为什么 style 放在头部 script 放在底部？」</p></blockquote><blockquote><p>参考答案：</p><p>浏览器在解析 HTML 时是从上到下进行解析的，当遇到样式和 JS 时，都会停止 HTML 解析，转而解析样式和执行 JS。而我们往往希望，页面的样式解析完成后再解析 HTML，这样可以避免页面闪烁，基于此，样式应该放到顶部；而相反的，我们希望在解析完 HTML 后再执行 JS，这样可以让用户尽快的看到页面，同时也让 JS 执行时能够拿到完整的 DOM 树，基于此，JS 代码应该放到底部。</p><p>不过，在 HTML5 中出现了 async 和 defer 属性，使用该属性可以更好的解决 JS 的问题，我们可以把 script 放到顶部，让浏览器尽快下载，但延迟执行。实际上，在新版本的 html-webpack-plugin 中，它已经这样做了。</p></blockquote><h2 id="_12-webpack-配置如何实现开发环境不使用-cdn、生产环境使用-cdn" tabindex="-1">12. webpack 配置如何实现开发环境不使用 cdn、生产环境使用 cdn？ <a class="header-anchor" href="#_12-webpack-配置如何实现开发环境不使用-cdn、生产环境使用-cdn" aria-hidden="true">#</a></h2><blockquote><p>要配置 CDN，有两个步骤：</p><ol><li>在 html 模板中直接加入 cdn 引用</li><li>在 webpack 配置中，加入<code>externals</code>配置，告诉 webpack 不要打包其中的模块，转而使用全局变量</li></ol><p>若要在开发环境中不使用 CDN，只需根据环境变量判断不同的环境，进行不同的打包处理即可。</p><ol><li>在 html 模板中使用 ejs 模板语法进行判断，只有在生产环境中引入 CDN</li><li>在 webpack 配置中，可以根据<code>p<wbr>rocess.env</code>中的环境变量进行判断是否使用<code>externals</code>配置</li><li>在<code>package.json</code>脚本中设置不同的环境变量完成打包或开发启动。</li></ol></blockquote><h2 id="_13-介绍一下-webpack4-中的-tree-shaking-的工作流程" tabindex="-1">13. 介绍一下 webpack4 中的 tree-shaking 的工作流程？ <a class="header-anchor" href="#_13-介绍一下-webpack4-中的-tree-shaking-的工作流程" aria-hidden="true">#</a></h2><blockquote><p>推荐阅读：<a href="https://tsejx.github.io/webpack-guidebook/principle-analysis/operational-principle/tree-shaking" target="_blank" rel="noreferrer">https://tsejx.github.io/webpack-guidebook/principle-analysis/operational-principle/tree-shaking</a></p></blockquote><blockquote><p>参考答案：</p><p>tree-shaking 仅支持 ESM 的静态导入语法，对于 CMJ 或者 ESM 中的动态导入不支持 tree shaking。</p><p>具体流程主要分为两步：标记和删除</p><ol><li><p>标记</p><p>webpack 在分析依赖时，会使用注释的方式对导入和导出进行标记，对于模块中没有被其他模块用到的导出标记为 unused harmony export</p></li><li><p>删除</p><p>之后在 Uglifyjs (或者其他类似的工具) 步骤进行代码精简，把标记为无用的代码删除。</p></li></ol></blockquote><h2 id="_14-说一下-webpack-loader-的作用是什么" tabindex="-1">14. 说一下 webpack loader 的作用是什么？ <a class="header-anchor" href="#_14-说一下-webpack-loader-的作用是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>用于转换代码。有时是因为 webpack 无法识别某些内容，比如图片、css 等，需要由 loader 将其转换为 JS 代码。有时是因为某些代码需要被特殊处理，比如 JS 兼容性的处理，需要由 loader 将其进一步转换。不管是什么情况，loader 的作用只有一个，就是转换代码。</p></blockquote><h2 id="_15-在开发过程中如果需要对已有模块进行扩展-如何进行开发保证调用方不受影响" tabindex="-1">15. 在开发过程中如果需要对已有模块进行扩展，如何进行开发保证调用方不受影响？ <a class="header-anchor" href="#_15-在开发过程中如果需要对已有模块进行扩展-如何进行开发保证调用方不受影响" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>实际上就是一个版本管理的问题。</p><p>如果此次模块升级只是修复了某一些 bug，作为补丁版本升级即可，不影响主版本和次版本号</p><p>如果此次模块升级会新增一些内容，完全兼容之前的 API，作为次版本升级即可</p><p>如果此次模块升级会修改之前的 API，则作为主版本升级</p><p>在开发项目时，让项目依赖模块的主版本，因此，当模块更新时，只要不是主版本更新，项目都可以非常方便的升级模块版本，无须改动任何代码。但若涉及主版本更新，项目可以完全无视此次版本更新，仍然使用之前的旧版本，无须改动任何代码；当然也可以升级主版本，但就会涉及代码的改动，这就好比跟将 vue2 升级到 vue3 会涉及大量改动一样。</p><p>而在开发模块时，在一开始就要精心设计 API，尽量保证 API 的接口稳定，不要经常变动主版本号。如果实在要更新主版本，就需要在一段时间内同时维护两个版本（新的主版本，旧的主版本），给予其他项目一定的升级时间。</p></blockquote><h2 id="_16-export-和-export-default-的区别是什么" tabindex="-1">16. export 和 export default 的区别是什么？ <a class="header-anchor" href="#_16-export-和-export-default-的区别是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>export 为普通导出，又叫做具名导出，顾名思义，它导出的数据必须带有命名，比如变量定义、函数定义这种带有命名的语句。在导出的模块对象中，命名即为模块对象的属性名。在一个模块中可以有多个具名导出</p><p>export default 为默认导出，在模块对象中名称固定为 default，因此无须命名，通常导出一个表达式或字面量。在一个模块中只能有一个默认导出。</p></blockquote><h2 id="_17-webpack-打包原理是什么" tabindex="-1">17. webpack 打包原理是什么？ <a class="header-anchor" href="#_17-webpack-打包原理是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><strong>初始化参数</strong>：从配置文件和 Shell 语句中读取与合并参数，得出最终的参数</li><li><strong>开始编译</strong>：用上一步得到的参数初始化 Compiler 对象，加载所有配置的插件，执行对象的 <code>run</code> 方法开始执行编译</li><li><strong>确定入口</strong>：根据配置中的 <code>entry</code> 找出所有的入口文件</li><li><strong>编译模块</strong>：从入口文件出发，调用所有配置的 <code>loader</code> 对模块进行翻译，再把翻译后的内容转换成 AST，通过对 AST 的分析找出该模块依赖的模块，再 <code>递归</code> 本步骤直到所有入口依赖的文件都经过了本步骤的处理</li><li><strong>完成模块编译</strong>：在经过第 4 步使用 <code>loader</code> 翻译完所有模块后，得到了每个模块被翻译后的最终内容以及它们之间的 <code>依赖关系图</code></li><li><strong>输出资源</strong>：根据入口和模块之间的依赖关系，组装成一个个包含多个模块的 <code>Chunk</code>，再把每个 Chunk 转换成一个单独的文件加入到输出列表，这步是可以修改输出内容的最后机会</li><li><strong>输出完成</strong>：在确定好输出内容后，根据配置确定输出的路径和文件名，把文件内容写入到文件系统</li></ol></blockquote><h2 id="_18-webpack-热更新原理是什么" tabindex="-1">18. webpack 热更新原理是什么？ <a class="header-anchor" href="#_18-webpack-热更新原理是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>当开启热更新后，页面中会植入一段 websocket 脚本，同时，开发服务器也会和客户端建立 websocket 通信，当源码发生变动时，webpack 会进行以下处理：</p><ol><li>webpack 重新打包</li><li>webpack-dev-server 检测到模块的变化，于是通过 webscoket 告知客户端变化已经发生</li><li>客户端收到消息后，通过 ajax 发送请求到开发服务器，以过去打包的 hash 值请求服务器的一个 json 文件</li><li>服务器告诉客户端哪些模块发生了变动，同时告诉客户端这次打包产生的新 hash 值</li><li>客户端再次用过去的 hash 值，以 JSONP 的方式请求变动的模块</li><li>服务器响应一个函数调用，用于更新模块的代码</li><li>此时，模块代码已经完成更新。客户端按照之前的监听配置，执行相应模块变动后的回调函数。</li></ol></blockquote><h2 id="_19-如何优化-webpack-的打包速度" tabindex="-1">19. 如何优化 webpack 的打包速度？ <a class="header-anchor" href="#_19-如何优化-webpack-的打包速度" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>noParse</p><p>很多第三方库本身就是已经打包好的代码，对于这种代码无须再进行解析，可以使用 noParse 配置排除掉这些第三方库</p></li><li><p>externals</p><p>对于一些知名的第三方库可以使用 CDN，这部分库可以通过 externals 配置不进行打包</p></li><li><p>限制 loader 的范围</p><p>在使用 loader 的时候，可以通过 exclude 排除掉一些不必要的编译，比如 babel-loader 对于那些已经完成打包的第三方库没有必要再降级一次，可以排除掉</p></li><li><p>开启 loader 缓存</p><p>可以利用<code>cache-loader</code>缓存 loader 的编译结果，避免在源码没有变动时反复编译</p></li><li><p>开启多线程编译</p><p>可以利用<code>thread-loader</code>开启多线程编译，提升编译效率</p></li><li><p>动态链接库</p><p>对于某些需要打包的第三方库，可以使用 dll 的方式单独对其打包，然后 DLLPlugin 将其整合到当前项目中，这样就避免了在开发中频繁去打包这些库</p></li></ol></blockquote><h2 id="_20-webpack-如何实现动态导入" tabindex="-1">20. webpack 如何实现动态导入？ <a class="header-anchor" href="#_20-webpack-如何实现动态导入" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>当遇到代码中包含动态导入语句时，webpack 会将导入的模块及其依赖分配到单独的一个 chunk 中进行打包，形成单独的打包结果。而动态导入的语句会被编译成一个普通的函数调用，该函数在执行时，会使用 JSONP 的方式动态的把分离出去的包加载到模块集合中。</p></blockquote><h2 id="_21-说一下-webpack-有哪几种文件指纹" tabindex="-1">21. 说一下 webpack 有哪几种文件指纹 <a class="header-anchor" href="#_21-说一下-webpack-有哪几种文件指纹" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ul><li><p>hash</p><p>hash 是跟整个项目的构建相关，只要项目里有文件更改，整个项目构建的 hash 值都会更改，并且全部文件都共用相同的 hash 值</p></li><li><p>chunkhash</p><p>每个打包过程单独的 hash 值，如果一个项目有多个 entry，则每个 entry 维护自己的 chunkhash。</p></li><li><p>contenthash</p><p>每个文件内容单独的 hash 值，它和打包结果文件内容有关，只要文件内容不变，contenthash 不变。</p></li></ul></blockquote><h2 id="_22-常用的-webpack-loader-都有哪些" tabindex="-1">22. 常用的 webpack Loader 都有哪些？ <a class="header-anchor" href="#_22-常用的-webpack-loader-都有哪些" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ul><li>cache-loader：启用编译缓存</li><li>thread-loader：启用多线程编译</li><li>css-loader：编译 css 代码为 js</li><li>file-loader：保存文件到输出目录，将文件内容转换成文件路径</li><li>postcss-loader：将 css 代码使用 postcss 进行编译</li><li>url-loader：将文件内容转换成 dataurl</li><li>less-loader：将 less 代码转换成 css 代码</li><li>sass-loader：将 sass 代码转换成 css 代码</li><li>vue-loader：编译单文件组件</li><li>babel-loader：对 JS 代码进行降级处理</li></ul></blockquote><h2 id="_23-说一下-webpack-常用插件都有哪些" tabindex="-1">23. 说一下 webpack 常用插件都有哪些？ <a class="header-anchor" href="#_23-说一下-webpack-常用插件都有哪些" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ul><li>clean-webpack-plugin：清除输出目录</li><li>copy-webpack-plugin：复制文件到输出目录</li><li>html-webpack-plugin：生成 HTML 文件</li><li>mini-css-extract-plugin：将 css 打包成单独文件的插件</li><li>HotModuleReplacementPlugin：热更新的插件</li><li>purifycss-webpack：去除无用的 css 代码</li><li>optimize-css-assets-webpack-plugin：优化 css 打包体积</li><li>uglify-js-plugin：对 JS 代码进行压缩、混淆</li><li>compression-webpack-plugin：gzip 压缩</li><li>webpack-bundle-analyzer：分析打包结果</li></ul></blockquote><h2 id="_24-使用-babel-loader-会有哪些问题-可以怎样优化" tabindex="-1">24. 使用 babel-loader 会有哪些问题，可以怎样优化？ <a class="header-anchor" href="#_24-使用-babel-loader-会有哪些问题-可以怎样优化" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li>如果不做特殊处理，babel-loader 会对所有匹配的模块进行降级，这对于那些已经处理好兼容性问题的第三方库显得多此一举，因此可以使用 exclude 配置排除掉这些第三方库</li><li>在旧版本的 babel-loader 中，默认开启了对 ESM 的转换，这样会导致 webpack 的 tree shaking 失效，因为 tree shaking 是需要保留 ESM 语法的，所以需要关闭 babel-loader 的 ESM 转换，在其新版本中已经默认关闭了。</li></ol></blockquote><h2 id="_25-babel-是如何对-class-进行编译的" tabindex="-1">25. babel 是如何对 class 进行编译的？ <a class="header-anchor" href="#_25-babel-是如何对-class-进行编译的" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>本质上就是把 class 语法转换成普通构造函数定义，并做了以下处理：</p><ol><li>增加了对 this 指向的检测</li><li>将原型方法和静态方法变为不可枚举</li><li>将整个代码放到了立即执行函数中，运行后返回构造函数本身</li></ol></blockquote><h2 id="_26-解释一下-babel-polyfill-的作用是什么" tabindex="-1">26. 解释一下 babel-polyfill 的作用是什么？ <a class="header-anchor" href="#_26-解释一下-babel-polyfill-的作用是什么" aria-hidden="true">#</a></h2><blockquote><p>说明：</p><p>babel-polyfill 已经是一个非常古老的项目了，babel 从 7.4 版本开始已不再支持它，转而使用更加强大的 core-js，此题也适用于问「core-js 的作用是什么」</p></blockquote><blockquote><p>参考答案：</p><p>默认情况下，babel 本身只转换新的语法，而不对新的 API 进行处理。由于旧的环境中无法支持新的 API，比如 IE6 无法支持 fetch api，这就需要一个补丁，用旧语言的特性实现一遍新的 API，babel-polyfill 就是用来做这件事的。</p></blockquote><h2 id="_27-解释一下-less-的-的操作符是做什么用的" tabindex="-1">27. 解释一下 less 的&amp;的操作符是做什么用的？ <a class="header-anchor" href="#_27-解释一下-less-的-的操作符是做什么用的" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>&amp;符号后面的内容会和父级选择器合并书写，即中间不加入空格字符</p></blockquote><h2 id="_28-在前端工程化中-可以进行哪些方面的优化" tabindex="-1">28. 在前端工程化中，可以进行哪些方面的优化？ <a class="header-anchor" href="#_28-在前端工程化中-可以进行哪些方面的优化" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>对传输性能的优化</p><ul><li><p>压缩和混淆</p><p>使用 Uglifyjs 或其他类似工具对打包结果进行压缩、混淆，可以有效的减少包体积</p></li><li><p>tree shaking</p><p>项目中尽量使用 ESM，可以有效利用 tree shaking 优化，降低包体积</p></li><li><p>抽离公共模块</p><p>将一些公共代码单独打包，这样可以充分利用浏览器缓存，其他代码变动后，不影响公共代码，浏览器可以直接从缓存中找到公共代码。</p><p>具体方式有多种，比如 dll、splitChunks</p></li><li><p>异步加载</p><p>对一些可以延迟执行的模块可以使用动态导入的方式异步加载它们，这样在打包结果中，它们会形成单独的包，同时，在页面一开始解析时并不需要加载它们，而是页面解析完成后，执行 JS 的过程中去加载它们。</p><p>这样可以显著提高页面的响应速度，在单页应用中尤其有用。</p></li><li><p>CDN</p><p>对一些知名的库使用 CDN，不仅可以节省打包时间，还可以显著提升库的加载速度</p></li><li><p>gzip</p><p>目前浏览器普遍支持 gzip 格式，因此可以将静态文件均使用 gzip 进行压缩</p></li><li><p>环境适配</p><p>有些打包结果中包含了大量兼容性处理的代码，但在新版本浏览器中这些代码毫无意义。因此，可以把浏览器分为多个层次，为不同层次的浏览器给予不同的打包结果。</p></li></ul></li><li><p>对打包过程的优化</p><ul><li><p>noParse</p><p>很多第三方库本身就是已经打包好的代码，对于这种代码无须再进行解析，可以使用 noParse 配置排除掉这些第三方库</p></li><li><p>externals</p><p>对于一些知名的第三方库可以使用 CDN，这部分库可以通过 externals 配置不进行打包</p></li><li><p>限制 loader 的范围</p><p>在使用 loader 的时候，可以通过 exclude 排除掉一些不必要的编译，比如 babel-loader 对于那些已经完成打包的第三方库没有必要再降级一次，可以排除掉</p></li><li><p>开启 loader 缓存</p><p>可以利用<code>cache-loader</code>缓存 loader 的编译结果，避免在源码没有变动时反复编译</p></li><li><p>开启多线程编译</p><p>可以利用<code>thread-loader</code>开启多线程编译，提升编译效率</p></li><li><p>动态链接库</p><p>对于某些需要打包的第三方库，可以使用 dll 的方式单独对其打包，然后 DLLPlugin 将其整合到当前项目中，这样就避免了在开发中频繁去打包这些库</p></li></ul></li><li><p>对开发体验的优化</p><ul><li><p>lint</p><p>使用 eslint、stylelint 等工具保证团队代码风格一致</p></li><li><p>HMR</p><p>使用热替换避免页面刷新导致的状态丢失，提升开发体验</p></li></ul></li></ol></blockquote><h2 id="_29-如果有一个工程打包特别大-如何进行优化" tabindex="-1">29. 如果有一个工程打包特别大-如何进行优化？ <a class="header-anchor" href="#_29-如果有一个工程打包特别大-如何进行优化" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>CDN</p><p>如果工程中使用了一些知名的第三方库，可以考虑使用 CDN，而不进行打包</p></li><li><p>抽离公共模块</p><p>如果工程中用到了一些大的公共库，可以考虑将其分割出来单独打包</p></li><li><p>异步加载</p><p>对于那些不需要在一开始就执行的模块，可以考虑使用动态导入的方式异步加载它们，以尽量减少主包的体积</p></li><li><p>压缩、混淆</p></li><li><p>tree shaking</p><p>尽量使用 ESM 语法进行导入导出，充分利用 tree shaking 去除无用代码</p></li><li><p>gzip</p><p>开启 gzip 压缩，进一步减少包体积</p></li><li><p>环境适配</p><p>有些打包结果中包含了大量兼容性处理的代码，但在新版本浏览器中这些代码毫无意义。因此，可以把浏览器分为多个层次，为不同层次的浏览器给予不同的打包结果。</p></li></ol></blockquote><h2 id="_30-webpack-怎么进行首屏加载的优化" tabindex="-1">30. webpack 怎么进行首屏加载的优化？ <a class="header-anchor" href="#_30-webpack-怎么进行首屏加载的优化" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>CDN</p><p>如果工程中使用了一些知名的第三方库，可以考虑使用 CDN，而不进行打包</p></li><li><p>抽离公共模块</p><p>如果工程中用到了一些大的公共库，可以考虑将其分割出来单独打包</p></li><li><p>异步加载</p><p>对于那些不需要在一开始就执行的模块，可以考虑使用动态导入的方式异步加载它们，以尽量减少主包的体积</p></li><li><p>压缩、混淆</p></li><li><p>tree shaking</p><p>尽量使用 ESM 语法进行导入导出，充分利用 tree shaking 去除无用代码</p></li><li><p>gzip</p><p>开启 gzip 压缩，进一步减少包体积</p></li><li><p>环境适配</p><p>有些打包结果中包含了大量兼容性处理的代码，但在新版本浏览器中这些代码毫无意义。因此，可以把浏览器分为多个层次，为不同层次的浏览器给予不同的打包结果。</p></li></ol></blockquote><h2 id="_31-介绍一下-webpack-scope-hoisting" tabindex="-1">31. 介绍一下 webpack scope hoisting？ <a class="header-anchor" href="#_31-介绍一下-webpack-scope-hoisting" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>scope hoisting 是 webpack 的内置优化，它是针对模块的优化，在生产环境打包时会自动开启。</p><p>在未开启scope hoisting时，webpack 会将每个模块的代码放置在一个独立的函数环境中，这样是为了保证模块的作用域互不干扰。</p><p>而 scope hoisting 的作用恰恰相反，是把多个模块的代码合并到一个函数环境中执行。在这一过程中，webpack 会按照顺序正确的合并模块代码，同时对涉及的标识符做适当处理以避免重名。</p><p>这样做的好处是减少了函数调用，对运行效率有一定提升，同时也降低了打包体积。</p><p>但 scope hoisting 的启用是有前提的，如果遇到某些模块多次被其他模块引用，或者使用了动态导入的模块，或者是非 ESM 的模块，都不会有 scope hoisting。</p></blockquote><h2 id="_32-webpack-proxy-工作原理-为什么能解决跨域" tabindex="-1">32. webpack proxy 工作原理，为什么能解决跨域？ <a class="header-anchor" href="#_32-webpack-proxy-工作原理-为什么能解决跨域" aria-hidden="true">#</a></h2><blockquote><p>说明：</p><p>严格来说，webpack 只是一个打包工具，它并没有 proxy 的功能，甚至连服务器的功能都没有。之所以能够在 webpack 中使用 proxy 配置，是因为它的一个插件，即 webpack-dev-server 的能力。</p><p>所以，此题应该问做：「webpack-dev-server 工作原理，为什么能解决跨域？」</p></blockquote><blockquote><p>参考答案：</p><p>首先，proxy 配置是针对开发环境的，对生产环境没有任何意义。</p><p>当我们通过 webpack-dev-server 启动开发服务器后，所有的打包资源都可以通过访问开发服务器获得。</p><p>与此同时，我们又配置了 proxy，当我们向开发服务器请求特定的地址时，开发服务器会将其代理到目标地址。因此，后续对代理地址的请求，就可以变为直接请求开发服务器。</p><p>这样一来，我们请求静态页面的域和请求代理地址的域就同源了，因为都是请求开发服务器，所以就不会产生跨域问题。</p></blockquote><h2 id="_33-组件发布的是不是所有依赖这个组件库的项目都需要升级" tabindex="-1">33. 组件发布的是不是所有依赖这个组件库的项目都需要升级？ <a class="header-anchor" href="#_33-组件发布的是不是所有依赖这个组件库的项目都需要升级" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>实际上就是一个版本管理的问题。</p><p>如果此次模块升级只是修复了某一些 bug，作为补丁版本升级即可，不影响主版本和次版本号</p><p>如果此次模块升级会新增一些内容，完全兼容之前的 API，作为次版本升级即可</p><p>如果此次模块升级会修改之前的 API，则作为主版本升级</p><p>在开发项目时，让项目依赖模块的主版本，因此，当模块更新时，只要不是主版本更新，项目都可以非常方便的升级模块版本，无须改动任何代码。但若涉及主版本更新，项目可以完全无视此次版本更新，仍然使用之前的旧版本，无须改动任何代码；当然也可以升级主版本，但就会涉及代码的改动，这就好比跟将 vue2 升级到 vue3 会涉及大量改动一样。</p><p>而在开发模块时，在一开始就要精心设计 API，尽量保证 API 的接口稳定，不要经常变动主版本号。如果实在要更新主版本，就需要在一段时间内同时维护两个版本（新的主版本，旧的主版本），给予其他项目一定的升级时间。</p></blockquote><h2 id="_34-开发过程中-如何进行公共组件的设计-字节跳动" tabindex="-1">34. 开发过程中，如何进行公共组件的设计？（字节跳动） <a class="header-anchor" href="#_34-开发过程中-如何进行公共组件的设计-字节跳动" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>确定使用场景</p><p>明确这个公共组件的需求是怎么产生的，它目前的使用场景有哪些，将来还可能出现哪些使用场景。</p><p>明确使用场景至关重要，它决定了这个组件的使用边界在哪，通用到什么程度，从而决定了这个组件的开发难度</p></li><li><p>设计组件功能</p><p>根据其使用场景，设计出组件的属性、事件、使用说明文档</p></li><li><p>测试用例</p><p>根据使用说明文档编写组件测试用例</p></li><li><p>完成开发</p><p>根据使用说明文档、测试用例完成开发</p></li></ol></blockquote><h2 id="_35-说一下项目里有做过哪些-webpack-上的优化-字节跳动" tabindex="-1">35. 说一下项目里有做过哪些 webpack 上的优化（字节跳动） <a class="header-anchor" href="#_35-说一下项目里有做过哪些-webpack-上的优化-字节跳动" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>对传输性能的优化</p><ul><li><p>压缩和混淆</p><p>使用 Uglifyjs 或其他类似工具对打包结果进行压缩、混淆，可以有效的减少包体积</p></li><li><p>tree shaking</p><p>项目中尽量使用 ESM，可以有效利用 tree shaking 优化，降低包体积</p></li><li><p>抽离公共模块</p><p>将一些公共代码单独打包，这样可以充分利用浏览器缓存，其他代码变动后，不影响公共代码，浏览器可以直接从缓存中找到公共代码。</p><p>具体方式有多种，比如 dll、splitChunks</p></li><li><p>异步加载</p><p>对一些可以延迟执行的模块可以使用动态导入的方式异步加载它们，这样在打包结果中，它们会形成单独的包，同时，在页面一开始解析时并不需要加载它们，而是页面解析完成后，执行 JS 的过程中去加载它们。</p><p>这样可以显著提高页面的响应速度，在单页应用中尤其有用。</p></li><li><p>CDN</p><p>对一些知名的库使用 CDN，不仅可以节省打包时间，还可以显著提升库的加载速度</p></li><li><p>gzip</p><p>目前浏览器普遍支持 gzip 格式，因此可以将静态文件均使用 gzip 进行压缩</p></li><li><p>环境适配</p><p>有些打包结果中包含了大量兼容性处理的代码，但在新版本浏览器中这些代码毫无意义。因此，可以把浏览器分为多个层次，为不同层次的浏览器给予不同的打包结果。</p></li></ul></li><li><p>对打包过程的优化</p><ul><li><p>noParse</p><p>很多第三方库本身就是已经打包好的代码，对于这种代码无须再进行解析，可以使用 noParse 配置排除掉这些第三方库</p></li><li><p>externals</p><p>对于一些知名的第三方库可以使用 CDN，这部分库可以通过 externals 配置不进行打包</p></li><li><p>限制 loader 的范围</p><p>在使用 loader 的时候，可以通过 exclude 排除掉一些不必要的编译，比如 babel-loader 对于那些已经完成打包的第三方库没有必要再降级一次，可以排除掉</p></li><li><p>开启 loader 缓存</p><p>可以利用<code>cache-loader</code>缓存 loader 的编译结果，避免在源码没有变动时反复编译</p></li><li><p>开启多线程编译</p><p>可以利用<code>thread-loader</code>开启多线程编译，提升编译效率</p></li><li><p>动态链接库</p><p>对于某些需要打包的第三方库，可以使用 dll 的方式单独对其打包，然后 DLLPlugin 将其整合到当前项目中，这样就避免了在开发中频繁去打包这些库</p></li></ul></li><li><p>对开发体验的优化</p><ul><li><p>lint</p><p>使用 eslint、stylelint 等工具保证团队代码风格一致</p></li><li><p>HMR</p><p>使用热替换避免页面刷新导致的状态丢失，提升开发体验</p></li></ul></li></ol></blockquote><h2 id="_36-具体说一下-splitchunksplugin-的使用场景及使用方法。-字节跳动" tabindex="-1">36. 具体说一下 splitchunksplugin 的使用场景及使用方法。（字节跳动） <a class="header-anchor" href="#_36-具体说一下-splitchunksplugin-的使用场景及使用方法。-字节跳动" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><p>公共模块</p><p>比如某些多页应用会有多个入口，从而形成多个 chunk，而这些 chunk 中用到了一些公共模块，为了减少整体的包体积，可以使用 splitchunksplugin 将公共模块分离出来。</p><p>可以配置 minChunks 来指定被多少个 chunk 引用时进行分包</p></li><li><p>并行下载</p><p>由于 HTML5 支持 defer 和 async，因此可以同时下载多个 JS 文件以充分利用带宽。如果打包结果是一个很大的文件，就无法利用到这一点。</p><p>可以利用 splitchunks 插件将文件进行拆分，通过配置 maxSize 属性指定包体积达到多大时进行拆分</p></li></ol></blockquote><h2 id="_37-描述一下-webpack-的构建流程-cvte" tabindex="-1">37. 描述一下 webpack 的构建流程？（CVTE） <a class="header-anchor" href="#_37-描述一下-webpack-的构建流程-cvte" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li><strong>初始化参数</strong>：从配置文件和 Shell 语句中读取与合并参数，得出最终的参数</li><li><strong>开始编译</strong>：用上一步得到的参数初始化 Compiler 对象，加载所有配置的插件，执行对象的 <code>run</code> 方法开始执行编译</li><li><strong>确定入口</strong>：根据配置中的 <code>entry</code> 找出所有的入口文件</li><li><strong>编译模块</strong>：从入口文件出发，调用所有配置的 <code>loader</code> 对模块进行翻译，再把翻译后的内容转换成 AST，通过对 AST 的分析找出该模块依赖的模块，再 <code>递归</code> 本步骤直到所有入口依赖的文件都经过了本步骤的处理</li><li><strong>完成模块编译</strong>：在经过第 4 步使用 <code>loader</code> 翻译完所有模块后，得到了每个模块被翻译后的最终内容以及它们之间的 <code>依赖关系图</code></li><li><strong>输出资源</strong>：根据入口和模块之间的依赖关系，组装成一个个包含多个模块的 <code>Chunk</code>，再把每个 Chunk 转换成一个单独的文件加入到输出列表，这步是可以修改输出内容的最后机会</li><li><strong>输出完成</strong>：在确定好输出内容后，根据配置确定输出的路径和文件名，把文件内容写入到文件系统</li></ol></blockquote><h2 id="_38-解释一下-webpack-插件的实现原理-cvte" tabindex="-1">38. 解释一下 webpack 插件的实现原理？（CVTE） <a class="header-anchor" href="#_38-解释一下-webpack-插件的实现原理-cvte" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>本质上，webpack 的插件是一个带有<code>apply</code>函数的对象。当 webpack 创建好 compiler 对象后，会执行注册插件的 apply 函数，同时将 compiler 对象作为参数传入。</p><p>在 apply 函数中，开发者可以通过 compiler 对象监听多个钩子函数的执行，不同的钩子函数对应 webpack 编译的不同阶段。当 webpack 进行到一定阶段后，会调用这些监听函数，同时将 compilation 对象传入。开发者可以使用 compilation 对象获取和改变 webpack 的各种信息，从而影响构建过程。</p></blockquote><h2 id="_39-有用过哪些插件做项目的分析吗-cvte" tabindex="-1">39. 有用过哪些插件做项目的分析吗？（CVTE） <a class="header-anchor" href="#_39-有用过哪些插件做项目的分析吗-cvte" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>用过 webpack-bundle-analyzer 分析过打包结果，主要用于优化项目打包体积</p></blockquote><h2 id="_40-什么是-babel-有什么作用" tabindex="-1">40. 什么是 babel，有什么作用？ <a class="header-anchor" href="#_40-什么是-babel-有什么作用" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><p>babel 是一个 JS 编译器，主要用于将下一代的 JS 语言代码编译成兼容性更好的代码。</p><p>它其实本身做的事情并不多，它负责将 JS 代码编译成为 AST，然后依托其生态中的各种插件对 AST 中的语法和 API 进行处理</p></blockquote><h2 id="_41-解释一下-npm-模块安装机制是什么" tabindex="-1">41. 解释一下 npm 模块安装机制是什么？ <a class="header-anchor" href="#_41-解释一下-npm-模块安装机制是什么" aria-hidden="true">#</a></h2><blockquote><p>参考答案：</p><ol><li>npm 会检查本地的 node_modules 目录中是否已经安装过该模块，如果已经安装，则不再重新安装</li><li>npm 检查缓存中是否有相同的模块，如果有，直接从缓存中读取安装</li><li>如果本地和缓存中均不存在，npm 会从 registry 指定的地址下载安装包，然后将其写入到本地的 node_modules 目录中，同时缓存起来。</li></ol></blockquote></div></div></main><!--[--><!--]--><footer class="VPDocFooter" data-v-ae7d01fc data-v-2813752b><!----><div class="prev-next" data-v-2813752b><div class="pager" data-v-2813752b><a class="pager-link prev" href="/interview/vue.html" data-v-2813752b><span class="desc" data-v-2813752b>Previous page</span><span class="title" data-v-2813752b>vue</span></a></div><div class="has-prev pager" data-v-2813752b><a class="pager-link next" href="/interview/%E6%B5%8F%E8%A7%88%E5%99%A8.html" data-v-2813752b><span class="desc" data-v-2813752b>Next page</span><span class="title" data-v-2813752b>浏览器</span></a></div></div></footer><!--[--><!--]--></div></div></div></div></div><!----><!--[--><!--]--></div></div>
    <script>__VP_HASH_MAP__ = JSON.parse("{\"article_index.md\":\"857a285c\",\"article_js 修改 css 变量.md\":\"f79a90a6\",\"alg_index.md\":\"e3a92443\",\"article_uniapp 原生开发细节.md\":\"1f0effae\",\"article_uniapp真机调试列表不显示手机.md\":\"8e696be7\",\"article_qiankun 微应用实践（续-1）.md\":\"2ce41ff7\",\"article_uniapp 混合开发注意事项.md\":\"3a3ed44f\",\"article_uniapp使用安卓模拟器真机调试.md\":\"b16535a3\",\"engineering_index.md\":\"94e96b75\",\"javascript_index.md\":\"aa65c718\",\"index.md\":\"3445c9d9\",\"vue_reactive原理.md\":\"d958340a\",\"article_vue组件开发规范.md\":\"eca49209\",\"net_index.md\":\"ba8c0037\",\"node_复制操作.md\":\"9eddc4d4\",\"article_不同版本 axios 的 content-type.md\":\"f29fdcab\",\"node_index.md\":\"91a4e7d9\",\"vue_index.md\":\"259b0a38\",\"react_index.md\":\"3261342c\",\"interview_index.md\":\"b87fd9dd\",\"vue_封装一个loading控制器.md\":\"19b31069\",\"node_执行 cmd.md\":\"fc1cb5f7\",\"article_前端读写文件.md\":\"0187a051\",\"vue_computed 的 set 用法.md\":\"f66e4f74\",\"article_qiankun 微应用实践（上）.md\":\"5a4ba0c0\",\"vue_ref原理.md\":\"006339e2\",\"article_qiankun 微应用实践（下）.md\":\"0a30ca2d\",\"javascript_柯里化.md\":\"625112bc\",\"article_vitepress常用语法.md\":\"67339de5\",\"engineering_webpack的cachegroups.md\":\"1d6a7f5b\",\"vue_父子组件生命周期顺序.md\":\"ea9b1339\",\"interview_浏览器.md\":\"e20c4f30\",\"javascript_promise.md\":\"e0424afd\",\"engineering_webpack3升级4.md\":\"19d0ea18\",\"article_问题排查之路.md\":\"d663183f\",\"node_删除操作.md\":\"ddef11ba\",\"engineering_webpack 动态引入的坑.md\":\"9d587510\",\"article_封装一个进度管理组件.md\":\"870757fa\",\"engineering_rollup开发esmodule.md\":\"65034df8\",\"article_单词按a-z排序.md\":\"40e5a040\",\"interview_promise.md\":\"613f982f\",\"node_压缩和解压.md\":\"daac03e4\",\"interview_vue.md\":\"76dce706\",\"interview_工程化.md\":\"deda9421\",\"interview_网络.md\":\"30fcaab5\",\"article_搬砖注意事项.md\":\"a594fa21\",\"interview_css-note.md\":\"d48d4f85\",\"article_vitepress emoji.md\":\"1d769177\",\"interview_javascript.md\":\"47fbffd4\"}")</script>
    <script type="module" async src="/assets/app.db63b7d7.js"></script>
    
  </body>
</html>